home *** CD-ROM | disk | FTP | other *** search
-
- /*
- ** Copyright (C) 1993 DJ Delorie, 24 Kirsten Ave, Rochester NH 03867-2954
- **
- ** This file is distributed under the terms listed in the document
- ** "copying.dj", available from DJ Delorie at the address above.
- ** A copy of "copying.dj" should accompany this file; if not, a copy
- ** should be available from where this file was obtained. This file
- ** may not be distributed without a verbatim copy of "copying.dj".
- **
- ** This file is distributed WITHOUT ANY WARRANTY; without even the implied
- ** warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- */
-
- /* Modified by Morten Welinder, terra@diku.dk, for use with full screen
- debugger. These changes are copyright 1994 by Morten Welinder. */
- /* Modified by Long Doan, ld@netrix.com, to reduce memory usage.
- These changes are copyrighted 1994-1995 by Long Doan. */
-
- #include <stdio.h>
- #include <fcntl.h>
- #include <string.h>
- #include <stdlib.h>
- #include <ctype.h>
- #include <dos.h>
- #include <sys/stat.h>
-
- #include "ed.h"
- #include "coff.h"
- #include "syms.h"
- #include "stab.h"
- #include "wild.h"
-
- /* END_OF_INCLUDES */
-
- #define DO_SYMS 1
- #define SYM_FILE_VERSION 0x00010005
-
- int undefined_symbol=0;
-
- #define Ofs(n) ((int)&(((TSS *)0)->n))
-
- struct {
- char *name;
- int size;
- int ofs;
- } regs[] = {
- {"%eip" , 4, Ofs(tss_eip) },
- {"%eflags", 4, Ofs(tss_eflags)},
- {"%eax" , 4, Ofs(tss_eax) },
- {"%ebx" , 4, Ofs(tss_ebx) },
- {"%ecx" , 4, Ofs(tss_ecx) },
- {"%edx" , 4, Ofs(tss_edx) },
- {"%esp" , 4, Ofs(tss_esp) },
- {"%ebp" , 4, Ofs(tss_ebp) },
- {"%esi" , 4, Ofs(tss_esi) },
- {"%edi" , 4, Ofs(tss_edi) },
- {"%ax" , 2, Ofs(tss_eax) },
- {"%bx" , 2, Ofs(tss_ebx) },
- {"%cx" , 2, Ofs(tss_ecx) },
- {"%dx" , 2, Ofs(tss_edx) },
- {"%ah" , 1, Ofs(tss_eax)+1 },
- {"%bh" , 1, Ofs(tss_ebx)+1 },
- {"%ch" , 1, Ofs(tss_ecx)+1 },
- {"%dh" , 1, Ofs(tss_edx)+1 },
- {"%al" , 1, Ofs(tss_eax) },
- {"%bl" , 1, Ofs(tss_ebx) },
- {"%cl" , 1, Ofs(tss_ecx) },
- {"%dl" , 1, Ofs(tss_edx) },
- {0 , 0, 0 }
- };
-
- #if !DO_SYMS
-
- void syms_init(char *fname) {}
- void syms_list(int byval) {}
- void syms_listwild(char *pattern) {}
-
- word32 syms_name2val(char *name)
- {
- if (isdigit(name[0]))
- {
- int v;
- if (strncmp(name, "0x", 2) == 0)
- sscanf(name+2, "%x", &v);
- else
- sscanf(name, "%d", &v);
- undefined_symbol = 0;
- return v;
- }
- else
- {
- undefined_symbol = 1;
- return 0;
- }
- }
-
- char *syms_val2name(word32 val, word32 *delta)
- {
- static char noname_buf[20];
- sprintf(noname_buf, "%#lx", val);
- *delta = 0;
- return noname_buf;
- }
-
- char *syms_val2line(word32 val, int *lineret, int exact)
- {
- return 0;
- }
-
- char *get_module(int count);
- {
- static char noname_buf[20];
- sprintf(noname_buf, "%s", "Why call me here?");
- return noname_buf;
- }
-
- word32 get_linenum(int filenum, int linenum);
- {
- return 0;
- }
-
- #else
-
- /* From the file */
-
- typedef struct SYM_ENTRY {
- word32 string_off;
- word8 type;
- word8 other;
- word16 desc;
- word32 val;
- } SYM_ENTRY;
-
- static FILHDR f_fh;
- static AOUTHDR f_ah;
- static SCNHDR *f_sh = NULL;
- static SYMENT *f_symtab = NULL;
- static SYM_ENTRY *f_aoutsyms = NULL;
- static AUXENT *f_aux = NULL;
- static LINENO **f_lnno = NULL;
- static char *f_string_table = NULL;
- static char *f_types = NULL;
-
- /* built internally */
-
- typedef struct {
- char *filename;
- word32 first_address;
- word32 last_address;
- LINENO *lines;
- int num_lines;
- } FileNode;
-
- static FileNode *files;
- static int num_files;
-
- typedef struct SymNode {
- char *name;
- word32 address;
- char type_c;
- } SymNode;
-
- typedef struct SymAddr {
- char *name;
- word32 address;
- char type_c;
- word32 range;
- } SymAddr;
- /* -----------------------------------------------------------------
- - Structures used to dump/read symbols to/from a file.
- ----------------------------------------------------------------- */
- typedef struct SymFileHeader {
- word32 version;
- word32 syms_num;
- word32 syms_size;
- word32 file_time;
- word32 files_num;
- word32 start_file;
- word32 file_size;
- } SymFileHeader;
-
- typedef struct SymFileEntry {
- word32 offset;
- } SymFileEntry;
-
- typedef struct HiloName {
- char *name;
- int index;
- } HiloName;
-
- typedef struct HiloAddr {
- word32 addr;
- int index;
- } HiloAddr;
- /* -----------------------------------------------------------------
- - Structures used to dump/read line numbers to/from a file.
- ----------------------------------------------------------------- */
- typedef struct FileFileEntry {
- char name[100];
- word32 lines_num;
- word32 first_addr;
- word32 last_addr;
- word32 start_line;
- } FileFileEntry;
-
- typedef struct LineInfo {
- word32 addr;
- word32 l_no;
- word32 range;
- } LineInfo;
-
- typedef struct CacheInfo {
- word32 b_addr;
- word32 e_addr;
- int cached_files;
- int *files_cached;
- word32 *begin;
- word32 *end;
- } CacheInfo;
- /* -----------------------------------------------------------------
- - Original variables used to store symbols.
- ----------------------------------------------------------------- */
- static SymNode *syms;
- static int num_syms;
- /* -----------------------------------------------------------------
- - New variables used to store symbols.
- ----------------------------------------------------------------- */
- #define SYM_CACHE_SIZE 100
- #define LINE_CACHE_SIZE 682
- #define LINE_CACHE_SKIP 100
- #define MAX_HILO_CACHE 33
- static FILE *sym_file;
- static SymFileHeader sym_header;
- static SymNode name_cache[SYM_CACHE_SIZE];
- static word32 name_cached[SYM_CACHE_SIZE];
- static SymAddr addr_cache[SYM_CACHE_SIZE];
- static HiloName *name_hilo_cache;
- static HiloAddr *addr_hilo_cache;
- static int name_in_cache = 0;
- static int addr_in_cache = 0;
- static int entry_to_free = 0;
- static int cached_name_end = 0;
- static int cached_name_free = 0;
- static int hilo_cache_size;
- static FileFileEntry *file_entries;
- static LINENO line_cache[LINE_CACHE_SIZE];
- static CacheInfo line_cache_info;
- static char dos_buffer[4096];
- /* -----------------------------------------------------------------
- - Utilities
- ----------------------------------------------------------------- */
- static int syms_sort_bn(const void *a, const void *b)
- { SymNode *sa = (SymNode *)a;
- SymNode *sb = (SymNode *)b;
- return strcmp(sa->name, sb->name);
- }
- /* ----------------------------------------------------------------- */
- static int syms_sort_bv(const void *a, const void *b)
- { SymAddr *sa = (SymAddr *)a;
- SymAddr *sb = (SymAddr *)b;
- return sa->address - sb->address;
- }
- /* ----------------------------------------------------------------- */
- static char *symndup(char *s, int len)
- { char c = s[len], *rv;
- s[len] = 0;
- rv = strdup(s);
- s[len] = c;
- return rv;
- }
- /* ----------------------------------------------------------------- */
- static void
- get_sym_name_by_num (SymNode *sym, word32 num)
- { word32 offset;
- int i;
- SymFileEntry entry;
-
- if (num >= num_syms)
- return;
-
- for (i = 0; i < cached_name_end; i++)
- if (name_cached[i] == num)
- { sym->address = name_cache[i].address;
- sym->type_c = name_cache[i].type_c;
- strcpy (sym->name, name_cache[i].name);
- return;
- }
- offset = num * sizeof (SymFileEntry) + sym_header.syms_size;
- fseek (sym_file, offset, SEEK_SET);
- fread (&entry, sizeof (SymFileEntry) , 1, sym_file);
- fseek (sym_file, entry.offset, SEEK_SET);
- fread (&(sym->address) , sizeof (word32), 1, sym_file);
- fread (&(sym->type_c) , sizeof (char) , 1, sym_file);
- fgets (sym->name, 150, sym_file);
- sym->name[strlen (sym->name) - 1] = 0;
-
- if (cached_name_end == SYM_CACHE_SIZE)
- { i = cached_name_free;
- cached_name_free++;
- if (cached_name_free == cached_name_end)
- cached_name_free = 0;
- } else
- { i = cached_name_end;
- cached_name_end++;
- name_cache[i].name = malloc (151);
- }
- name_cache[i].address = sym->address;
- name_cache[i].type_c = sym->type_c;
- strcpy (name_cache[i].name, sym->name);
- name_cached[i] = num;
- }
- /* ----------------------------------------------------------------- */
- static void
- get_sym_addr_by_num (SymNode *sym, word32 num)
- { word32 offset;
- SymFileEntry entry;
-
- if (num >= num_syms)
- return;
- offset = (num + num_syms) * sizeof (SymFileEntry) + sym_header.syms_size;
- fseek (sym_file, offset, SEEK_SET);
- fread (&entry, sizeof (SymFileEntry) , 1, sym_file);
- fseek (sym_file, entry.offset, SEEK_SET);
- fread (&(sym->address) , sizeof (word32) , 1, sym_file);
- fread (&(sym->type_c) , sizeof (char) , 1, sym_file);
- fgets (sym->name, 150, sym_file);
- sym->name[strlen (sym->name) - 1] = 0;
- }
- /* ----------------------------------------------------------------- */
- static void
- init_cache (void)
- { int hi, lo, count, c_hi, c_lo, interval;
- char temp[151];
- SymNode sym;
-
- for (hilo_cache_size = MAX_HILO_CACHE; hilo_cache_size > num_syms;
- hilo_cache_size--)
- ;
- if (!(hilo_cache_size % 2))
- hilo_cache_size--;
- if (hilo_cache_size == 1)
- hilo_cache_size = 0;
- if (hilo_cache_size <= 0)
- { hilo_cache_size = 0;
- return;
- }
- name_hilo_cache = malloc (hilo_cache_size * sizeof (HiloName));
- addr_hilo_cache = malloc (hilo_cache_size * sizeof (HiloAddr));
- count = hilo_cache_size;
- hi = num_syms - 1;
- lo = 0;
- interval = num_syms / (hilo_cache_size - 1);
- c_hi = hilo_cache_size - 1;
- c_lo = 0;
- sym.name = temp;
- while (count > 1)
- { get_sym_name_by_num (&sym, lo);
- name_hilo_cache[c_lo].name = strdup (sym.name);
- name_hilo_cache[c_lo].index = lo;
- get_sym_name_by_num (&sym, hi);
- name_hilo_cache[c_hi].name = strdup (sym.name);
- name_hilo_cache[c_hi].index = hi;
- get_sym_addr_by_num (&sym, lo);
- addr_hilo_cache[c_lo].addr = sym.address;
- addr_hilo_cache[c_lo].index = lo;
- get_sym_addr_by_num (&sym, hi);
- addr_hilo_cache[c_hi].addr = sym.address;
- addr_hilo_cache[c_hi].index = hi;
- count -= 2;
- hi -= interval;
- lo += interval;
- if (lo > hi)
- lo = hi;
- c_hi--;
- c_lo++;
- }
- get_sym_name_by_num (&sym, lo);
- name_hilo_cache[c_lo].name = strdup (sym.name);
- name_hilo_cache[c_lo].index = lo;
- sym.name = temp;
- get_sym_addr_by_num (&sym, lo);
- addr_hilo_cache[c_lo].addr = sym.address;
- addr_hilo_cache[c_lo].index = lo;
-
- line_cache_info.cached_files = 0;
- line_cache_info.files_cached = malloc (sizeof (int));
- line_cache_info.begin = malloc (sizeof (word32));
- line_cache_info.end = malloc (sizeof (word32));
- }
- /* ----------------------------------------------------------------- */
- static void
- get_name_hilo (char *name, int *hi, int *lo)
- { int c_hi, c_lo;
- if (!hilo_cache_size)
- { *hi = -1;
- *lo = -1;
- return;
- }
- c_hi = hilo_cache_size - 1;
- c_lo = 0;
- while ((c_hi >= 0) && (strcmp (name, name_hilo_cache[c_hi].name) <= 0))
- c_hi--;
- if (c_hi < hilo_cache_size - 1)
- c_hi++;
- while ((c_lo <= c_hi) && (strcmp (name, name_hilo_cache[c_lo].name) >= 0))
- c_lo++;
- if (c_lo > 0)
- c_lo--;
- *hi = name_hilo_cache[c_hi].index;
- *lo = name_hilo_cache[c_lo].index;
- }
- /* ----------------------------------------------------------------- */
- static void
- get_addr_hilo (word32 addr, int *hi, int *lo)
- { int c_hi, c_lo;
- if (!hilo_cache_size)
- { *hi = -1;
- *lo = -1;
- return;
- }
- c_hi = hilo_cache_size - 1;
- c_lo = 0;
- if (addr > addr_hilo_cache[c_hi].addr ||
- addr < addr_hilo_cache[c_lo].addr)
- { *hi = -1;
- *lo = -1;
- return;
- }
- while ((c_hi >= 0) && (addr <= addr_hilo_cache[c_hi].addr))
- c_hi--;
- if (c_hi < hilo_cache_size - 1)
- c_hi++;
- while ((c_lo <= c_hi) && (addr >= addr_hilo_cache[c_lo].addr))
- c_lo++;
- if (c_lo > 0)
- c_lo--;
- *hi = addr_hilo_cache[c_hi].index;
- *lo = addr_hilo_cache[c_lo].index;
- }
- /* ----------------------------------------------------------------- */
- static int valid_symbol(int i)
- { char *sn;
- if (f_symtab[i].e.e.e_zeroes)
- sn = f_symtab[i].e.e_name;
- else
- sn = f_string_table + f_symtab[i].e.e.e_offset;
- if (sn[0] != '_')
- return 0;
- if (strncmp(sn, "___gnu_compiled", 15) == 0)
- return 0;
- if (strcmp(sn, "__DYNAMIC") == 0)
- return 0;
- return 1;
- }
- /* ----------------------------------------------------------------- */
- static void process_coff(FILE *fd, long ofs)
- { int i, f, s, f_pending;
- LINENO *l = 0;
- int l_pending;
- word32 strsize;
- char *name;
-
- fseek(fd, ofs, 0);
- fread(&f_fh, 1, FILHSZ, fd);
- fread(&f_ah, 1, AOUTSZ, fd);
- f_sh = (SCNHDR *)malloc(f_fh.f_nscns * SCNHSZ);
- f_types = (char *)malloc(f_fh.f_nscns);
- f_lnno = (LINENO **)malloc(f_fh.f_nscns * sizeof(LINENO *));
- fread(f_sh, f_fh.f_nscns, SCNHSZ, fd);
-
- for (i=0; i<f_fh.f_nscns; i++)
- { if (f_sh[i].s_flags & STYP_TEXT)
- f_types[i] = 'T';
- if (f_sh[i].s_flags & STYP_DATA)
- f_types[i] = 'D';
- if (f_sh[i].s_flags & STYP_BSS)
- f_types[i] = 'B';
- if (f_sh[i].s_nlnno)
- { fseek(fd, ofs + f_sh[i].s_lnnoptr, 0L);
- f_lnno[i] = (LINENO *)malloc(f_sh[i].s_nlnno * LINESZ);
- fread(f_lnno[i], LINESZ, f_sh[i].s_nlnno, fd);
- } else
- f_lnno[i] = 0;
- }
-
- fseek(fd, ofs + f_fh.f_symptr + f_fh.f_nsyms * SYMESZ, 0);
- fread(&strsize, 1, 4, fd);
- f_string_table = (char *)malloc(strsize);
- fread(f_string_table+4, 1, strsize-4, fd);
- f_string_table[0] = 0;
-
- fseek(fd, ofs+f_fh.f_symptr, 0);
- f_symtab = (SYMENT *)malloc(f_fh.f_nsyms * SYMESZ);
- fread(f_symtab, SYMESZ, f_fh.f_nsyms, fd);
- f_aux = (AUXENT *)f_symtab;
-
- num_syms = num_files = 0;
- for (i=0; i<f_fh.f_nsyms; i++)
- { switch (f_symtab[i].e_sclass)
- { case C_FILE:
- num_files++;
- break;
- case C_EXT:
- case C_STAT:
- if (!valid_symbol(i))
- break;
- num_syms++;
- break;
- }
- i += f_symtab[i].e_numaux;
- }
-
- files = (FileNode *)malloc(num_files * sizeof(FileNode));
-
- syms = (SymNode *)malloc(num_syms * sizeof(SymNode));
-
- f = s = f_pending = l_pending = 0;
- for (i=0; i<f_fh.f_nsyms; i++)
- { switch (f_symtab[i].e_sclass)
- { case C_FILE:
- if (f_aux[i+1].x_file.x_n.x_zeroes)
- /* -----------------------------------------------------------------
- - This will return in a lost of 16 bytes in memory when the name is freed.
- ----------------------------------------------------------------- */
- files[f].filename = symndup(f_aux[i+1].x_file.x_fname, 16);
- else
- files[f].filename = f_string_table + f_aux[i+1].x_file.x_n.x_offset;
- files[f].lines = 0;
- f_pending = 1;
- f++;
- break;
- case C_EXT:
- case C_STAT:
- if (f_symtab[i].e.e.e_zeroes)
- name = f_symtab[i].e.e_name;
- else
- name = f_string_table + f_symtab[i].e.e.e_offset;
- if (f_pending && strcmp(name, ".text") == 0)
- { files[f-1].first_address = f_symtab[i].e_value;
- files[f-1].last_address = f_symtab[i].e_value + f_aux[i+1].x_scn.x_scnlen - 1;
- files[f-1].num_lines = f_aux[i+1].x_scn.x_nlinno;
- f_pending = 0;
- }
- if (ISFCN(f_symtab[i].e_type))
- { int scn = f_symtab[i].e_scnum - 1;
- l = f_lnno[scn] + ((f_aux[i+1].x_sym.x_fcnary.x_fcn.x_lnnoptr - f_sh[scn].s_lnnoptr)/LINESZ);
- l_pending = 1;
- l->l_addr.l_paddr = f_symtab[i].e_value;
- }
- if (!valid_symbol(i))
- break;
- syms[s].address = f_symtab[i].e_value;
- if (f_symtab[i].e.e.e_zeroes)
- /* -----------------------------------------------------------------
- - This will return in a lost of 8 bytes in memory when the name is freed.
- ----------------------------------------------------------------- */
- syms[s].name = symndup(f_symtab[i].e.e_name, 8);
- else
- syms[s].name = f_string_table + f_symtab[i].e.e.e_offset;
- switch (f_symtab[i].e_scnum)
- { case 1 ... 10:
- syms[s].type_c = f_types[f_symtab[i].e_scnum-1];
- break;
- case N_UNDEF:
- syms[s].type_c = 'U';
- break;
- case N_ABS:
- syms[s].type_c = 'A';
- break;
- case N_DEBUG:
- syms[s].type_c = 'D';
- break;
- }
- if (f_symtab[i].e_sclass == C_STAT)
- syms[s].type_c += 'a' - 'A';
-
- s++;
- break;
- case C_FCN:
- if (f_pending && files[f-1].lines == 0)
- { files[f-1].lines = l;
- }
- if (l_pending)
- { int lbase = f_aux[i+1].x_sym.x_misc.x_lnsz.x_lnno - 1;
- int i2;
- l->l_lnno = lbase;
- l++;
- for (i2=0; l[i2].l_lnno; i2++)
- l[i2].l_lnno += lbase;
- l_pending = 0;
- }
- break;
- }
- i += f_symtab[i].e_numaux;
- }
- }
- /* ----------------------------------------------------------------- */
- static void process_aout(FILE *fd, long ofs)
- { GNU_AOUT header;
- word32 string_table_length;
- int nsyms, i, f, s, l;
-
- fseek(fd, ofs, 0);
- fread(&header, 1, sizeof(header), fd);
-
- fseek(fd, ofs + sizeof(header) + header.tsize + header.dsize + header.txrel + header.dtrel, 0);
- nsyms = header.symsize / sizeof(SYM_ENTRY);
- f_aoutsyms = (SYM_ENTRY *)malloc(header.symsize);
- fread(f_aoutsyms, 1, header.symsize, fd);
-
- fread(&string_table_length, 1, 4, fd);
- f_string_table = (char *)malloc(string_table_length);
- fread(f_string_table+4, 1, string_table_length-4, fd);
- f_string_table[0] = 0;
-
- num_files = num_syms = 0;
- for (i=0; i<nsyms; i++)
- { char *symn = f_string_table + f_aoutsyms[i].string_off;
- char *cp;
- switch (f_aoutsyms[i].type & ~N_EXT)
- { case N_SO:
- if (symn[strlen(symn)-1] == '/')
- break;
- num_files++;
- break;
- case N_TEXT:
- cp = symn + strlen(symn) - 2;
- if (strncmp(symn, "___gnu", 6) == 0 ||
- strcmp(cp, "d.") == 0 /* as in gcc_compiled. */ ||
- strcmp(cp, ".o") == 0)
- break;
- case N_DATA:
- case N_ABS:
- case N_BSS:
- case N_FN:
- case N_SETV:
- case N_SETA:
- case N_SETT:
- case N_SETD:
- case N_SETB:
- case N_INDR:
- num_syms ++;
- break;
- }
- }
-
- syms = (SymNode *)malloc(num_syms * sizeof(SymNode));
- memset(syms, num_syms * sizeof(SymNode), 0);
- files = (FileNode *)malloc(num_files * sizeof(FileNode));
- memset(files, num_files * sizeof(FileNode), 0);
-
- f = s = 0;
- for (i=0; i<nsyms; i++)
- { char c, *cp;
- char *symn = f_string_table + f_aoutsyms[i].string_off;
- switch (f_aoutsyms[i].type & ~N_EXT)
- { case N_SO:
- if (symn[strlen(symn)-1] == '/')
- break;
- if (f && files[f-1].last_address == 0)
- files[f-1].last_address = f_aoutsyms[i].val - 1;
- files[f].filename = symn;
- files[f].first_address = f_aoutsyms[i].val;
- f ++;
- break;
- case N_SLINE:
- files[f-1].num_lines++;
- break;
- case N_TEXT:
- cp = symn + strlen(symn) - 2;
- if (strncmp(symn, "___gnu", 6) == 0 ||
- strcmp(cp, "d.") == 0 /* as in gcc_compiled. */ ||
- strcmp(cp, ".o") == 0)
- { if (f && files[f-1].last_address == 0)
- files[f-1].last_address = f_aoutsyms[i].val - 1;
- break;
- }
- c = 't';
- goto sym_c;
- case N_DATA:
- c = 'd';
- goto sym_c;
- case N_ABS:
- c = 'a';
- goto sym_c;
- case N_BSS:
- c = 'b';
- goto sym_c;
- case N_FN:
- c = 'f';
- goto sym_c;
- case N_SETV:
- c = 'v';
- goto sym_c;
- case N_SETA:
- c = 'v';
- goto sym_c;
- case N_SETT:
- c = 'v';
- goto sym_c;
- case N_SETD:
- c = 'v';
- goto sym_c;
- case N_SETB:
- c = 'v';
- goto sym_c;
- case N_INDR:
- c = 'i';
- sym_c:
- syms[s].name = symn;
- syms[s].address = f_aoutsyms[i].val;
- syms[s].type_c = (f_aoutsyms[i].type & N_EXT) ? (c+'A'-'a') : c;
- s ++;
- break;
- }
- }
-
- l = f = 0;
- for (i=0; i<nsyms; i++)
- { char *symn = f_string_table + f_aoutsyms[i].string_off;
- switch (f_aoutsyms[i].type & ~N_EXT)
- { case N_SO:
- if (symn[strlen(symn)-1] == '/')
- break;
- files[f].lines = (LINENO *)malloc(files[f].num_lines * sizeof(LINENO));
- f++;
- l = 0;
- break;
- case N_SLINE:
- files[f-1].lines[l].l_addr.l_paddr = f_aoutsyms[i].val;
- files[f-1].lines[l].l_lnno = f_aoutsyms[i].desc;
- l ++;
- break;
- }
- }
-
- }
- /* ----------------------------------------------------------------- */
- static void process_file(FILE *fd, long ofs)
- { short s, exe[2];
- fseek(fd, ofs, 0);
- fread(&s, 1, 2, fd);
- switch (s)
- { case 0x5a4d: /* .exe */
- fread(exe, 2, 2, fd);
- ofs += (long)exe[1] * 512L;
- if (exe[0])
- ofs += (long)exe[0] - 512L;
- process_file(fd, ofs);
- break;
- case 0x014c: /* .coff */
- process_coff(fd, ofs);
- break;
- case 0x010b: /* a.out ZMAGIC */
- case 0x0107: /* a.out object */
- process_aout(fd, ofs);
- break;
- }
- }
- /* -----------------------------------------------------------------
- - Interface fuctions.
- ----------------------------------------------------------------- */
- void syms_init(char *fname)
- { FILE *fd = fopen(fname, "rb");
- int i, len = strlen (fname);
- word32 org_time;
- char *symfilename = alloca (len + 4);
- /* struct stat statbuf; */
- int used = 0, left = 4096;
-
- if (fd == 0)
- { perror(fname);
- } else
- { SymFileEntry *name_entries, *addr_entries;
- word32 sym_offset;
- SymAddr *syms_byaddr;
-
- getftime (fileno (fd), (struct ftime *)&org_time);
- strcpy (symfilename, sympath);
- strcpy (symfilename + strlen (symfilename), symname);
- symfilename[strlen (symfilename) + 1] = 0;
- symfilename[strlen (symfilename)] = '.';
- strcpy (symfilename + strlen (symfilename), symext);
- /* if (stat(symfilename, &statbuf) != -1) */
- /* if (0 == access (symfilename, 4)) */
- sym_file = fopen (symfilename, "rb");
- /* else
- sym_file = 0; */
- if (sym_file)
- { fread (&sym_header, sizeof (SymFileHeader), 1, sym_file);
- if (sym_header.file_time == org_time &&
- sym_header.version == SYM_FILE_VERSION)
- { num_syms = sym_header.syms_num;
- num_files = sym_header.files_num;
- fseek (sym_file, 0, SEEK_END);
- sym_offset = ftell (sym_file);
- if (sym_offset == sym_header.file_size)
- { printf ("Use symbol file %s\n", symfilename);
- init_cache ();
- fseek (sym_file, sym_header.start_file, SEEK_SET);
- file_entries = malloc (num_files * sizeof (FileFileEntry));
- fread (file_entries, sizeof (FileFileEntry), num_files, sym_file);
- return;
- }
- }
- fclose (sym_file);
- }
- printf ("Create symbol file %s\n", symfilename);
- sym_file = fopen (symfilename, "wb");
- process_file(fd, 0);
- fclose(fd);
- sym_header.version = SYM_FILE_VERSION;
- sym_header.syms_num = num_syms;
- sym_header.file_time = org_time;
- sym_header.files_num = num_files;
- fwrite (&sym_header, sizeof (SymFileHeader), 1, sym_file);
- name_entries = (SymFileEntry *)malloc (num_syms * sizeof (SymFileEntry));
- addr_entries = (SymFileEntry *)malloc (num_syms * sizeof (SymFileEntry));
- /* -----------------------------------------------------------------
- - Sort the original symbol table by name, and move to file.
- ----------------------------------------------------------------- */
- sym_offset = sizeof (SymFileHeader);
- qsort(syms, num_syms, sizeof(SymNode), syms_sort_bn);
- for (i = 0; i < num_syms; i++)
- { name_entries[i].offset = sym_offset;
- len = strlen (syms[i].name) + 1;
- if (left < 5 + len)
- { fwrite (dos_buffer, 1, used, sym_file);
- used = 0;
- left = 4096;
- }
- *(word32 *)(dos_buffer + used) = syms[i].address;
- *(dos_buffer + used + 4) = syms[i].type_c;
- strcpy (dos_buffer + used + 5, syms[i].name);
- *(dos_buffer + used + len + 4) = '\n';
- used += len + 5;
- left -= len + 5;
- sym_offset += len + 5;
- /* free (syms[i].name); */
- }
- if (used)
- fwrite (dos_buffer, 1, used, sym_file);
-
- sym_header.syms_size = sym_offset;
- /* -----------------------------------------------------------------
- - Sort the original symbol table by address, and record their offset.
- ----------------------------------------------------------------- */
- syms_byaddr = (SymAddr *)malloc(num_syms * sizeof(SymAddr));
- for (i = 0; i < num_syms; i++)
- { memcpy(&(syms_byaddr[i]), &(syms[i]), sizeof(SymNode));
- syms_byaddr[i].range = i;
- }
- qsort(syms_byaddr, num_syms, sizeof(SymAddr), syms_sort_bv);
- for (i = 0; i < num_syms; i++)
- addr_entries[i].offset = name_entries[syms_byaddr[i].range].offset;
- free (syms);
- free (syms_byaddr);
- /* -----------------------------------------------------------------
- - Write the offset tables to the file and free them.
- ----------------------------------------------------------------- */
- fwrite (name_entries, sizeof (SymFileEntry), num_syms, sym_file);
- fwrite (addr_entries, sizeof (SymFileEntry), num_syms, sym_file);
- free (name_entries);
- free (addr_entries);
- sym_header.start_file = sym_header.syms_size +
- 2 * num_syms * sizeof (SymFileEntry);
- sym_header.file_size = sym_header.start_file +
- num_files * sizeof (FileFileEntry);
- /* -----------------------------------------------------------------
- - Write the line number information to the file, and free them.
- ----------------------------------------------------------------- */
- file_entries = malloc (num_files * sizeof (FileFileEntry));
- for (i = 0; i < num_files; i++)
- { file_entries[i].lines_num = files[i].num_lines;
- file_entries[i].start_line = sym_header.file_size;
- file_entries[i].first_addr = files[i].first_address;
- file_entries[i].last_addr = files[i].last_address;
- strncpy (file_entries[i].name, files[i].filename, 99);
- sym_header.file_size += files[i].num_lines * LINESZ;
- }
- fwrite (file_entries, sizeof (FileFileEntry), num_files, sym_file);
- for (i = 0; i < num_files; i++)
- { fwrite (files[i].lines, LINESZ, files[i].num_lines, sym_file);
- free (files[i].lines);
- /* free (files[i].filename); */
- }
- free (files);
-
- free (f_string_table);
- free (f_sh);
- free (f_symtab);
- free (f_aoutsyms);
- free (f_aux);
- free (f_lnno);
- free (f_types);
- /* -----------------------------------------------------------------
- - Write the adjusted header to the file.
- ----------------------------------------------------------------- */
- fseek (sym_file, 0, SEEK_SET);
- fwrite (&sym_header, sizeof (SymFileHeader), 1, sym_file);
- fclose (sym_file);
- /* -----------------------------------------------------------------
- - Test the intergity of the file.
- ----------------------------------------------------------------- */
- sym_file = fopen (symfilename, "rb");
- fseek (sym_file, 0, SEEK_END);
- sym_offset = ftell (sym_file);
- if (sym_offset != sym_header.file_size)
- { fclose (sym_file);
- perror (symfilename);
- }
- }
- init_cache ();
- }
- /* ----------------------------------------------------------------- */
- static void
- get_sym_by_name (SymNode *sym, char *name)
- { int hi, lo, mid, found = 0;
- int err;
-
- get_name_hilo (name, &hi, &lo);
- if (hi < 0 || lo < 0)
- { sym->name = 0;
- return;
- }
- sym->name = malloc (151);
- do
- { mid = (hi + lo) / 2;
- get_sym_name_by_num (sym, mid);
- err = strcmp (name, sym->name);
- if (err == 0)
- found = 1;
- else if (err < 0)
- hi = mid;
- else
- lo = mid;
- err = (hi - lo <= 1) && !found;
- } while (!found && !err);
- if (err)
- { free (sym->name);
- sym->name = 0;
- }
- }
- /* ----------------------------------------------------------------- */
- static int
- get_sym_by_addr (word32 addr)
- { int hi, lo, mid;
- word32 offset, start_offset;
- SymFileEntry entry;
- SymNode sym_n;
-
- if (addr < 0x1000)
- return (-1);
-
- for (mid = 0; mid < addr_in_cache; mid++)
- if (addr_cache[mid].address <= addr && addr <= addr_cache[mid].range)
- return (mid);
-
- get_addr_hilo (addr, &hi, &lo);
- if (hi < 0 || lo < 0)
- return (-1);
- sym_n.name = malloc (151);
- start_offset = sym_header.syms_size + num_syms * sizeof (SymFileEntry);
- do
- { mid = (hi + lo) / 2;
- get_sym_addr_by_num (&sym_n, mid);
- if (sym_n.address == addr)
- break;
- if (sym_n.address > addr)
- hi = mid;
- else
- lo = mid;
- } while (hi - lo > 1);
-
- if (sym_n.address > addr)
- mid--; /* the last below was it */
- if (mid >= 0)
- { get_sym_addr_by_num (&sym_n, mid);
- offset = (mid + 1) * sizeof (SymFileEntry) + start_offset;
- fseek (sym_file, offset, SEEK_SET);
- fread (&entry, sizeof (SymFileEntry) , 1, sym_file);
- fseek (sym_file, entry.offset, SEEK_SET);
- fread (&start_offset, sizeof (word32), 1, sym_file);
- } else
- { free (sym_n.name);
- return (-1);
- }
-
- if (addr_in_cache == SYM_CACHE_SIZE)
- { free (addr_cache[entry_to_free].name);
- mid = entry_to_free;
- entry_to_free++;
- if (entry_to_free == addr_in_cache)
- entry_to_free = 0;
- } else
- { mid = addr_in_cache;
- addr_in_cache++;
- }
- addr_cache[mid].name = sym_n.name;
- addr_cache[mid].address = sym_n.address;
- addr_cache[mid].type_c = sym_n.type_c;
- addr_cache[mid].range = start_offset - 1;
- return (mid);
- }
- /* ----------------------------------------------------------------- */
- static int
- lookup_sym_byname(char *name, int idx, int ofs)
- { SymNode sym;
- char temp[151];
-
- sprintf (temp, "%s%s", ofs ? "_" : "", name);
- temp[idx + ofs + 1] = '\0';
- get_sym_by_name (&sym, temp);
- if (!(sym.name))
- return (-1);
- if (name_in_cache)
- free (name_cache[0].name);
- else
- name_in_cache = 1;
- name_cache[0].name = strdup (sym.name);
- name_cache[0].address = sym.address;
- name_cache[0].type_c = sym.type_c;
- free (sym.name);
- return (0);
- }
- /* ----------------------------------------------------------------- */
- static void
- get_line_block (int file, int line, LINENO *l_info)
- { fseek (sym_file, file_entries[file].start_line + line * LINESZ, SEEK_SET);
- fread (l_info, LINESZ, LINE_CACHE_SIZE, sym_file);
- }
- /* ----------------------------------------------------------------- */
- static void
- do_fill (word32 addr, int file)
- { int start_line = 0, end_line = 0, count;
- int start_file = file, end_file = file, total_lines;
-
- do {
- start_line = end_line;
- get_line_block (file, start_line, line_cache);
- end_line = start_line + LINE_CACHE_SIZE;
- if (end_line > file_entries[file].lines_num)
- end_line = file_entries[file].lines_num;
- for (count = start_line; count < end_line; count++)
- { if (line_cache[count - start_line].l_addr.l_paddr >= addr)
- { start_line = count - LINE_CACHE_SKIP;
- total_lines = file_entries[file].lines_num;
- while (start_line < 0 && start_file > 0)
- { total_lines += file_entries[--start_file].lines_num;
- start_line += file_entries[start_file].lines_num;
- }
- if (start_line < 0)
- start_line = 0;
- get_line_block (start_file, start_line, line_cache);
- while (total_lines < LINE_CACHE_SIZE && ++end_file < num_files)
- total_lines += file_entries[end_file].lines_num;
- if (end_file == num_files)
- end_file--;
- if (total_lines < LINE_CACHE_SIZE)
- line_cache_info.e_addr =
- line_cache[total_lines - 1].l_addr.l_paddr;
- else
- line_cache_info.e_addr =
- line_cache[LINE_CACHE_SIZE - 1].l_addr.l_paddr;
- line_cache_info.cached_files = 0;
- while (start_file <= end_file)
- { line_cache_info.cached_files++;
- line_cache_info.files_cached =
- realloc (line_cache_info.files_cached,
- line_cache_info.cached_files * sizeof (int));
- line_cache_info.files_cached[line_cache_info.cached_files - 1] =
- start_file;
- line_cache_info.begin =
- realloc (line_cache_info.begin,
- line_cache_info.cached_files * sizeof (word32));
- line_cache_info.begin[line_cache_info.cached_files - 1] =
- file_entries[start_file].first_addr;
- line_cache_info.end =
- realloc (line_cache_info.end,
- line_cache_info.cached_files * sizeof (word32));
- line_cache_info.end[line_cache_info.cached_files - 1] =
- file_entries[start_file].last_addr;
- start_file++;
- }
- line_cache_info.b_addr = line_cache[0].l_addr.l_paddr;
- return;
- }
- }
- } while (end_line < file_entries[file].lines_num);
- }
- /* ----------------------------------------------------------------- */
- static void
- fill_line_cache (word32 addr)
- { int f;
- for (f = 0; f < num_files; f++)
- { if (addr >= file_entries[f].first_addr &&
- addr <= file_entries[f].last_addr &&
- file_entries[f].lines_num)
- { do_fill (addr, f);
- return;
- }
- }
- }
- /* ----------------------------------------------------------------- */
- static void
- lookup_file_num (word32 addr, int *file)
- { int i;
- for (i = 0; i < line_cache_info.cached_files; i++)
- { if (line_cache_info.begin[i] <= addr && addr <= line_cache_info.end[i])
- { *file = line_cache_info.files_cached[i];
- return;
- }
- }
- *file = -1;
- return;
- }
- /* ----------------------------------------------------------------- */
- static int
- lookup_line_cache (word32 addr, int exact, int *file)
- { int i;
-
- if (!line_cache_info.cached_files)
- fill_line_cache (addr);
- if (addr < line_cache_info.b_addr || addr > line_cache_info.e_addr)
- return (-1);
- for (i = 0; i < LINE_CACHE_SIZE; i++)
- { if (line_cache[i].l_addr.l_paddr == addr)
- { lookup_file_num (addr, file);
- return (line_cache[i].l_lnno);
- }
- if (line_cache[i].l_addr.l_paddr > addr)
- { if (exact)
- return (-1);
- else
- { lookup_file_num (addr, file);
- return (line_cache[i].l_lnno);
- }
- }
- }
- return (-1);
- }
- /* ----------------------------------------------------------------- */
- static word32
- get_line_by_num (int file, int num, int exact)
- { int start_line, end_line = 0, count;
- LINENO *l_no;
-
- l_no = (LINENO *)dos_buffer;
- do {
- start_line = end_line; /* Overlap last entry */
- get_line_block (file, start_line, l_no);
- end_line = start_line + (4096 / LINESZ);
- if (end_line >= file_entries[file].lines_num)
- end_line = file_entries[file].lines_num - 1;
- for (count = start_line; count <= end_line; count++)
- { if (l_no[count - start_line].l_lnno == num)
- return (l_no[count - start_line].l_addr.l_paddr);
- if (l_no[count - start_line].l_lnno > num)
- { if (exact)
- return (0xffffffff);
- else if (count > start_line)
- return (l_no[count - 1 - start_line].l_addr.l_paddr);
- else return (l_no[0].l_addr.l_paddr);
- }
- }
- } while (end_line < file_entries[file].lines_num - 1);
- if (exact)
- return (0xffffffff);
- return (l_no[end_line - start_line].l_addr.l_paddr);
- }
- /* ----------------------------------------------------------------- */
- word32 syms_name2val(char *name)
- { int idx, sign=1, i;
- word32 v = 0;
- char *cp;
-
- undefined_symbol = 0;
- idx = 0;
- sscanf(name, "%s", name);
- if (name[0] == 0)
- return 0;
- if (name[0] == '-')
- { sign = -1;
- name++;
- } else if (name[0] == '+')
- name++;
- if (isdigit(name[0]))
- { if (sign == -1)
- return -strtoul(name, 0, 0);
- return strtoul(name, 0, 0);
- }
- cp = strpbrk(name, "+-");
- if (cp)
- idx = cp-name;
- else
- idx = strlen(name);
-
- if (name[0] == '%') /* register */
- { for (i=0; regs[i].name; i++)
- if (strncmp(name, regs[i].name, idx) == 0)
- { switch (regs[i].size)
- { case 1:
- v = *(word8 *)((word8 *)(&a_tss) + regs[i].ofs);
- break;
- case 2:
- v = *(word16 *)((word8 *)(&a_tss) + regs[i].ofs);
- break;
- case 4:
- v = *(word32 *)((word8 *)(&a_tss) + regs[i].ofs);
- break;
- }
- return v + syms_name2val(name+idx);
- }
- }
-
- for (i=0; i<idx; i++)
- if (name[i] == '#')
- { int f, lnum;
- word32 l_addr;
-
- sscanf(name+i+1, "%d", &lnum);
- for (f=0; f<num_files; f++)
- { if ((strncmp(name, file_entries[f].name, i) == 0) &&
- (file_entries[f].name[i] == 0))
- { l_addr = get_line_by_num (f, lnum, 1);
- if (l_addr != 0xffffffff)
- return l_addr + syms_name2val(name+idx);
- undefined_symbol = 1;
- return 0;
- }
- }
- undefined_symbol = 1;
- return 0;
- }
-
- i = lookup_sym_byname(name, idx, 0);
- if (i == -1)
- i = lookup_sym_byname(name, idx, 1);
- if (i != -1)
- return name_cache[i].address * sign + syms_name2val(name+idx);
- undefined_symbol = 1;
- return 0;
- }
- /* ----------------------------------------------------------------- */
- static char noname_buf[11];
- /* ----------------------------------------------------------------- */
- char *syms_val2name(word32 val, word32 *delta)
- { int pos;
-
- if (delta)
- *delta = 0;
- if (num_syms <= 0)
- goto noname;
- pos = get_sym_by_addr (val);
- if (pos < 0)
- goto noname;
-
- if (delta)
- *delta = val - addr_cache[pos].address;
- return (addr_cache[pos].name);
- noname:
- sprintf(noname_buf, "%#lx", val);
- return noname_buf;
- }
- /* ----------------------------------------------------------------- */
- char *syms_val2line(word32 val, int *lineret, int exact)
- { int f;
- if (val < line_cache_info.b_addr || val > line_cache_info.e_addr)
- fill_line_cache (val);
- *lineret = lookup_line_cache (val, exact, &f);
- if (*lineret == -1)
- return 0;
- return (file_entries[f].name);
- }
- /* ----------------------------------------------------------------- */
- static void
- get_lots_sym_name_by_num (SymNode *sym, word32 num)
- { static word32 i = 0;
- static int used = 0, left = 4096;
- word32 offset, j, k;
- SymFileEntry entry;
-
- if (num >= num_syms)
- return;
- if ((i == 0) || (num == 0) || (num != i + 1) || (left < 300))
- { offset = num * sizeof (SymFileEntry) + sym_header.syms_size;
- fseek (sym_file, offset, SEEK_SET);
- fread (&entry, sizeof (SymFileEntry) , 1, sym_file);
- offset = entry.offset;
- fseek (sym_file, offset, SEEK_SET);
- fread (dos_buffer , 1 , 4096, sym_file);
- used = 0;
- left = 4096;
- }
- i = num;
- sym->address = *(word32 *)(dos_buffer + used);
- sym->type_c = dos_buffer[used + 4];
- for (j = used + 5, k = 0; dos_buffer[j] != '\n'; j++, k++)
- sym->name[k] = dos_buffer[j];
- sym->name[k++] = 0;
- j++;
- used = j;
- left = 4096 - used;
- }
- /* ----------------------------------------------------------------- */
- static char wild_buf[200];
- char *
- syms_makewild(word32 sym_num)
- { int lnum;
- char *name;
- SymNode sym;
-
- sym.name = alloca (151);
- get_sym_name_by_num (&sym, sym_num);
- name = syms_val2line(sym.address, &lnum, 0);
- sprintf (wild_buf, "0x%08lx %c %s", sym.address, sym.type_c, sym.name);
- if (name)
- sprintf (wild_buf + strlen (wild_buf),
- ", line %d of %s", lnum, name);
- return (wild_buf);
- }
- /* ----------------------------------------------------------------- */
- void
- syms_get (word32 sym_num, word32 *address, char *type_c)
- { SymNode sym;
-
- sym.name = alloca (151);
- get_sym_name_by_num (&sym, sym_num);
- *address = sym.address;
- *type_c = sym.type_c;
- }
- /* ----------------------------------------------------------------- */
- void syms_listwild(char *pattern,
- void (*handler)(word32))
- { int i;
- SymNode sym;
- sym.name = alloca (151);
-
- for (i=0; i<num_syms; i++)
- { get_lots_sym_name_by_num (&sym, i);
- if (wild(pattern, sym.name))
- handler (i);
- }
- }
- /* ----------------------------------------------------------------- */
- char *get_module(int count)
- { char *s;
-
- if ((count < 0) || (count == num_files))
- { undefined_symbol = 1;
- return 0;
- }
- s = strdup(file_entries[count].name);
- return s;
- }
- /* ----------------------------------------------------------------- */
- word32 get_linenum(int filenum, int linenum)
- { if ((filenum < 0) || (filenum >= num_files))
- { undefined_symbol = 1;
- return 0;
- }
- return (get_line_by_num (filenum, linenum, 0));
- }
-
- #endif
-